home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 25 / Cream of the Crop 25.iso / program / vgatx10s.zip / VGATEXT.CPP < prev    next >
C/C++ Source or Header  |  1997-04-12  |  19KB  |  591 lines

  1. /*
  2.  * This file is part of the VgaText C++ Programming Library
  3.  *
  4.  * Copyright (c) 1995, 1997 by Branislav L. Slantchev
  5.  * A fine product of Silicon Creations, Inc. (gargoyle)
  6.  *
  7.  * This library is free software; you can redistribute it and/or
  8.  * modify it under the terms of the License which accompanies this
  9.  * software. This library is distributed in the hope that it will
  10.  * be useful, but without any warranty; without even the implied
  11.  * warranty of merchantability or fitness for a particular purpose.
  12.  *
  13.  * You should have received a copy of the License along with this
  14.  * library, in the file LICENSE.DOC; if not, write to the address
  15.  * below to receive a copy via electronic mail.
  16.  *
  17.  * You can reach Branislav L. Slantchev (Silicon Creations, Inc.)
  18.  * at bslantch@cs.angelo.edu. The file SUPPORT.DOC has the current
  19.  * telephone numbers and the postal address for contacts.
  20. */
  21. #include "vgatext.h"
  22. #include "comdef.h"
  23.  
  24. /*
  25.  * v g a   t e x t   m o d e   e f f e c t   c l a s s
  26.  * ──────────────────────────────────────────────────────────────────────────
  27.  * this module implements the special vga text mode effect class
  28. */
  29. #ifndef INCLUDED_ASSERT_H
  30. #define INCLUDED_ASSERT_H
  31. #include <assert.h>
  32. #endif
  33.  
  34. #ifndef INCLUDED_DOS_H
  35. #define INCLUDED_DOS_H
  36. #include <dos.h>
  37. #endif
  38.  
  39. #ifndef INCLUDED_STRING_H
  40. #define INCLUDED_STRING_H
  41. #include <string.h>
  42. #endif
  43.  
  44. #undef  disable
  45. #undef  enable
  46. #define TIMER_INTERRUPT   8
  47.  
  48. // used by the Grade??? routines and the grade calculation function
  49. static struct{
  50.     char increment;   // value to add to the color value
  51.     char fixupRange;  // range of palettes than need the 'fixup' added
  52.     char fixup;       // fixup (either 1 or -1) that is sometimes needed
  53. } redScale, greenScale, blueScale;
  54.  
  55. static union REGS   regs;
  56. static struct SREGS sreg;
  57. #define VideoInt()  int86(0x10, ®s, ®s)
  58. #define xVideoInt() int86x(0x10, ®s, ®s, &sreg)
  59.  
  60. Boolean zVgaText::vgaCard = False;
  61. Boolean zVgaText::initVga = False;
  62. Boolean zVgaText::restoreBlink = False;
  63. Boolean zVgaText::timerSet = False;
  64. void interrupt (*zVgaText::timerVector)(...) = 0;
  65. uchar  zVgaText::origDac[768];
  66. uchar  zVgaText::origPal[17];
  67. uchar  zVgaText::origPageMode;
  68. uchar  zVgaText::origDispPage;
  69. uchar  zVgaText::pal[17];
  70. uchar  zVgaText::dac[768];
  71. ushort zVgaText::delayTicks = 1;
  72. ushort zVgaText::countdown = 9;
  73. char   zVgaText::delta = 1;
  74. char   zVgaText::nCurPalette = 0;
  75.  
  76. /*
  77.  * wait for a top of vertical retrace (must call before switching palettes)
  78.  * not used in this module. since we are using int 10h to do the work, we
  79.  * don't need to sync with the retrace (the interrupt handler does that)
  80. */
  81. #if 0
  82. static void
  83. wait_vertical_retrace()
  84. {
  85. /*
  86.     while( (inportb (0x3da) & 8) )
  87.         ;
  88.     while( !(inportb (0x3da) & 8) )
  89.         ;
  90. */
  91.     _asm mov  dx,0x3da
  92. VRT:
  93.     _asm in   al,dx
  94.     _asm test al,8
  95.     _asm jnz  VRT
  96. NoVRT:
  97.     _asm in   al,dx
  98.     _asm test al,8
  99.     _asm jz   NoVRT
  100. }
  101. #endif
  102.  
  103. zVgaText::zVgaText()
  104. {
  105.     assert(False == initVga);
  106.     if( False != (vgaCard = Detect()) ) resume();
  107. }
  108.  
  109. zVgaText::~zVgaText()
  110. {
  111.     suspend();
  112.     initVga = False;
  113. }
  114.  
  115. void
  116. zVgaText::resume()
  117. {
  118.     // save the 16 VGA palette registers plus the border color
  119.     regs.x.ax = 0x1009;
  120.     sreg.es   = FP_SEG((uchar far *)&origPal[0]);
  121.     regs.x.dx = FP_OFF((uchar far *)&origPal[0]);
  122.     xVideoInt();
  123.     // save the original DAC rgb registers (all 256 of them)
  124.     regs.x.ax = 0x1017;
  125.     regs.x.bx = 0;
  126.     regs.x.cx = 256;
  127.     sreg.es   = FP_SEG((uchar far *)&origDac[0]);
  128.     regs.x.dx = FP_OFF((uchar far *)&origDac[0]);
  129.     xVideoInt();
  130.     // save the original paging mode and display page
  131.     regs.x.ax = 0x101A;
  132.     VideoInt();
  133.     origPageMode = regs.h.bl;
  134.     origDispPage = regs.h.bh;
  135.     // set our own user palette registers. we use the values from 0 to 15
  136.     // to make it easier to map attributes directly for DAC palettes. we
  137.     // also just copy the current border color from the original setting
  138.     for( int i = 0; i < 16; ++i ) pal[i] = (uchar)i;
  139.     pal[16] = origPal[16];
  140.     regs.x.ax = 0x1002;
  141.     sreg.es   = FP_SEG((uchar far *)&pal[0]);
  142.     regs.x.dx = FP_OFF((uchar far *)&pal[0]);
  143.     xVideoInt();
  144.     // set our own video DAC rgb palettes (16 of them, 16 colors each, with
  145.     // 3 bytes per color (RGB).
  146.     ResetPalettes();
  147.     LoadPalettes();
  148.     // set the paging mode to 1 (DAC is treated as 16 palettes of 16 colors)
  149.     regs.x.ax = 0x1013;
  150.     regs.x.bx = 0x0100;
  151.     VideoInt();
  152.     // set some initial values here
  153.     delayTicks = 1;
  154.     delta = 1;
  155. }
  156.  
  157. // suspend the timer and restore the settings
  158. void
  159. zVgaText::suspend()
  160. {
  161.     // restore the original timer handler
  162.     disable();
  163.     // restore the original 16 vga registers and border color
  164.     regs.x.ax = 0x1002;
  165.     sreg.es   = FP_SEG((uchar far *)&origPal[0]);
  166.     regs.x.dx = FP_OFF((uchar far *)&origPal[0]);
  167.     xVideoInt();
  168.     // restore all 256 DAC rgb registers
  169.     regs.x.ax = 0x1012;
  170.     regs.x.bx = 0;
  171.     regs.x.cx = 256;
  172.     sreg.es   = FP_SEG((uchar far *)&origDac[0]);
  173.     regs.x.dx = FP_OFF((uchar far *)&origDac[0]);
  174.     xVideoInt();
  175.     // restore the paging mode
  176.     regs.x.ax = 0x1013;
  177.     regs.h.bl = 0;
  178.     regs.h.bh = origPageMode;
  179.     VideoInt();
  180.     // restore the display page
  181.     regs.x.ax = 0x1013;
  182.     regs.h.bl = 1;
  183.     regs.h.bh = origDispPage;
  184.     VideoInt();
  185.     // check to see if we need to restore the blinking
  186.     if( restoreBlink )
  187.     {
  188.         regs.x.ax = 0x1003;
  189.         regs.h.bl = 1;
  190.         VideoInt();
  191.         restoreBlink = False;
  192.     }
  193. }
  194.  
  195. // reset the user DAC rgb definition in all 16 palettes to original. this
  196. // does NOT place the color definition into the VGA DAC. note that all
  197. // 0x33 values should actually be 0x3F to match the default palette set up
  198. // by the BIOS. thse look a little dimmer, but they do leave some room
  199. // for special affects like pulsing and fading for those too...
  200. void
  201. zVgaText::ResetPalettes()
  202. {
  203.     static const char cpOrigDac[48] =
  204.         "\x00\x00\x00"  // black
  205.         "\x00\x00\x2A"  // blue
  206.         "\x00\x2A\x00"  // green
  207.         "\x00\x2A\x2A"  // cyan
  208.         "\x2A\x00\x00"  // red
  209.         "\x2A\x00\x2A"  // magenta
  210.         "\x2A\x15\x00"  // brown (close enough)
  211.         "\x2A\x2A\x2A"  // light gray
  212.         "\x15\x15\x15"  // dark gray (close enough)
  213.         "\x00\x00\x3F"  // light blue
  214.         "\x00\x3F\x00"  // light green
  215.         "\x00\x3F\x3F"  // light cyan
  216.         "\x3F\x00\x00"  // light red
  217.         "\x3F\x00\x3F"  // light magenta
  218.         "\x3F\x3F\x00"  // yellow
  219.         "\x3F\x3F\x3F"; // white
  220.  
  221.     for( int i = 0; i < 16; ++i ) memcpy(dac + (i*48), cpOrigDac, 48);
  222.     nCurPalette = 0;
  223. }
  224.  
  225. // load all 16 palettes into the VGA
  226. void
  227. zVgaText::LoadPalettes()
  228. {
  229.     regs.x.ax = 0x1012;
  230.     regs.x.bx = 0;
  231.     regs.x.cx = 256;
  232.     sreg.es   = FP_SEG((uchar far *)&dac[0]);
  233.     regs.x.dx = FP_OFF((uchar far *)&dac[0]);
  234.     xVideoInt();
  235. }
  236.  
  237. // change the mode between blinking and 4-bit backgrounds
  238. void
  239. zVgaText::EnableBlink(Boolean enable)
  240. {
  241.     regs.x.ax = 0x1003;
  242.     // if we are enabling blinking, clear the flag for the restore
  243.     if( enable )
  244.     {
  245.         regs.h.bl = 1;
  246.         restoreBlink = False;
  247.     }
  248.     // if we are enabling 4-bit backgrounds, set the blink restore flag
  249.     else
  250.     {
  251.         regs.h.bl = 0;
  252.         restoreBlink = True;
  253.     }
  254.     VideoInt();
  255. }
  256.  
  257. // enable the timer intercept handler. this is the routine that cycles
  258. // through the 16 custom palettes. only works if the timer is installed.
  259. void
  260. zVgaText::enable()
  261. {
  262.     if( !timerSet )
  263.     {
  264.         timerSet = True;
  265.         countdown = 1;
  266.         nCurPalette = 0;
  267.         timerVector = getvect(TIMER_INTERRUPT);
  268.         setvect(TIMER_INTERRUPT, timerHandler);
  269.     }
  270. }
  271.  
  272. // disable the timer intercept handler. this will freeze the palette at
  273. // the argument given by the 'nPalette' parameter (between 0 and 15)
  274. void
  275. zVgaText::disable(char nPalette)
  276. {
  277.     if( timerSet )
  278.     {
  279.         setvect(TIMER_INTERRUPT, timerVector);
  280.         regs.x.ax = 0x1013;
  281.         regs.h.bl = 1;
  282.         regs.h.bh = nPalette & 0x0F;  // just to make sure
  283.         VideoInt();
  284.         timerSet = False;
  285.     }
  286. }
  287.  
  288. // get a pointer to the RGB definition of the 'nAttrib' attribute in the
  289. // user DAC palette 'nPalette'. both values can range from 0 to 15.
  290. uchar*
  291. zVgaText::GetDacPtr(char attrib, char palette)
  292. {
  293.     int nColor, nPalette;
  294.  
  295.     // make sure we stay within the limits
  296.     attrib  &= 0x0F;
  297.     palette &= 0x0F;
  298.     // map the attribute into the VGA registers. since we initialize
  299.     // those to their indexes, they drop out of the picture and the
  300.     // attribute will map directly to the same color. since the user
  301.     // may have modified those, we need the step anyway (and just to
  302.     // be safe, make sure the user hasn't put large numbers there..)
  303.     nColor = pal[attrib] & 0x0F;
  304.     // since each color has 3-byte RGB definitions, multiply the
  305.     // resulting color number by 3 to get to the correct byte offset
  306.     nColor = nColor * 3;
  307.     // the DAC palette itself consists of 16 palettes, with 16 colors
  308.     // each. and each color has 3-byte RGB definitions. to get the the
  309.     // offset for the palette, we multiply the palette number by 48
  310.     // which is the size of each individual palette (16 colors * 3 bytes)
  311.     nPalette = palette * 48;
  312.     // the offset into the palette for the requested attribute will be
  313.     // the nColor value we already calculated, and the pointer returned
  314.     // is to the position within the user DAC palette (nPalette + nColor)
  315.     return &dac[nPalette + nColor];
  316. }
  317.  
  318. // sets the number of ticks to skip before a palette change occurs in the
  319. // interrupt handler. this will also reset the current setting. this
  320. // routine will work even if the timer is not enabled (saves the setting)
  321. void
  322. zVgaText::SetDelay(ushort nTicks)
  323. {
  324.     delayTicks = nTicks;
  325.     countdown = delayTicks;
  326. }
  327.  
  328. // set the delta skip step: this is the number of palettes that the timer
  329. // intercept will skip when a palette change is required. this also makes
  330. // sure that the current palette is a multiple of delta
  331. void
  332. zVgaText::SetDelta(char nDelta)
  333. {
  334.     delta = nDelta & 0x0F;  // stay within the limits
  335.     nCurPalette = (nCurPalette / delta) * delta; // fix the palette number
  336. }
  337.  
  338. // create a pulsing color definition. this is color which changes its
  339. // intensity over the palettes. this routine will not modify palette 0,
  340. // but all the ones following it. 'aDelta' is the value to add at each step
  341. // and 'nAttrib' is the color attribute that we are modifying
  342. void
  343. zVgaText::PulseColor(char nAttrib, char aDelta)
  344. {
  345.     PulseColor(nAttrib, aDelta, 0, 15);
  346. }
  347.  
  348. // this is the actual routine which creates the pulsing definitions. note
  349. // that nAttrib should be between 0 and 15 and the end palette should be
  350. // larger than the start. the start palette is not modified. this routine
  351. // does not load the palettes into the vga DAC registers (use LoadPalettes)
  352. void
  353. zVgaText::PulseColor(char nAttrib, char aDelta, char nStart, char nEnd)
  354. {
  355.     if( nEnd > 0 && nEnd < 16 && nEnd > nStart )
  356.     {
  357.         uchar *dacptr = GetDacPtr(nAttrib, nStart);
  358.         while( ++nStart <= nEnd )
  359.         {
  360.             // get the values from the current palette
  361.             uchar r = dacptr[0], g = dacptr[1], b = dacptr[2];
  362.             // get to the next palette by adding the size of the
  363.             // palette to the pointer to the attrib in the current one
  364.             // the size of each palette is 48 bytes, so this is enough
  365.             dacptr += 48;
  366.             // increment non-zero primaries only, make sure we stay within
  367.             // the maximum limits (63 is the maximum color saturation)
  368.             if( 0 != dacptr[0] ) dacptr[0] = min(r + aDelta, 0x3F);
  369.             if( 0 != dacptr[1] ) dacptr[1] = min(g + aDelta, 0x3F);
  370.             if( 0 != dacptr[2] ) dacptr[2] = min(b + aDelta, 0x3F);
  371.         }
  372.     }
  373. }
  374.  
  375. // set the RGB color definition for all 16 palettes (see SetColor() below)
  376. void
  377. zVgaText::SetColor(char nAttrib, char rgb[3])
  378. {
  379.     SetColor(nAttrib, rgb, 0, 15);
  380. }
  381.  
  382. // the actual routine which sets the color definition for a range of
  383. // palettes. this function sets the color for attribute 'nAttrib' to
  384. // the RGB values in the 'aRGB' parameter. the input is verified, the
  385. // attribute is forced within limits. if the requested range is invalid,
  386. // nothing is done. the new palettes are not sent to the vga DAC registers
  387. void
  388. zVgaText::SetColor(char nAttrib, char aRGB[3], char nStart, char nEnd)
  389. {
  390.     if( nEnd > 0 && nEnd < 16 && nStart <= nEnd )
  391.     {
  392.         uchar *dacptr = GetDacPtr(nAttrib, nStart);
  393.         while( nStart++ <= nEnd )
  394.         {
  395.             // set the color definition to the RGB values, make sure
  396.             // that we stay within the maximum color saturation allowed
  397.             dacptr[0] = aRGB[0] & 0x3F;
  398.             dacptr[1] = aRGB[1] & 0x3F;
  399.             dacptr[2] = aRGB[2] & 0x3F;
  400.             dacptr += 48; // get to the next palette's color definition
  401.         }
  402.     }
  403. }
  404.  
  405. // grade a color definition starting with the RGB values in palette 0
  406. // and ending with the 'aRGB' values in palette 15 (all palettes are used)
  407. // the first palette is not modified and the new values are not loaded
  408. // into the vga DAC registers (use LoadPalettes() to do that)
  409. void
  410. zVgaText::GradeColor(char nAttrib, char aRGB[3])
  411. {
  412.     GradeColor(nAttrib, aRGB, 0, 15);
  413. }
  414.  
  415. // grades a color definition starting with the RGB values in the nStart
  416. // palette and slowly progressing towards the 'aRGB' values over the
  417. // range of palettes between nStart and nEnd. this causes the color to
  418. // gradually change between the starting and end values. the first palette
  419. // is not modified and the new palettes are not loaded into the vga DAC
  420. void
  421. zVgaText::GradeColor(char nAttrib, char aRGB[3], char nStart, char nEnd)
  422. {
  423.     if( 0 < nEnd && nEnd < 16 && nEnd > nStart )
  424.     {
  425.         // calculate the three color grade values that will change the
  426.         // starting RGB into the ending RGB over a range of palettes
  427.         uchar *dacptr = GetDacPtr(nAttrib, nStart);
  428.         CalcScale((char *)dacptr, aRGB, nEnd - nStart);
  429.         for( int i = 0; i <= nEnd - nStart; ++i )
  430.         {
  431.             uchar r = dacptr[0], g = dacptr[1], b = dacptr[2];
  432.             dacptr += 48;  // get to the next palette's color definition
  433.             // add the increments and check if we need to use the fixup
  434.             dacptr[0] = r + redScale.increment;
  435.             if( i < redScale.fixupRange ) dacptr[0] += redScale.fixup;
  436.             dacptr[1] = g + greenScale.increment;
  437.             if( i < greenScale.fixupRange ) dacptr[1] += greenScale.fixup;
  438.             dacptr[2] = b + blueScale.increment;
  439.             if( i < blueScale.fixupRange ) dacptr[2] += blueScale.fixup;
  440.         }
  441.     }
  442. }
  443.  
  444. // calculate the color gradation values. each gradation is computed so
  445. // that the original value can gradually change into the ending value
  446. // over a range of registers. to do that, we calculate the increment that
  447. // will get us there. since sometimes the increment will not actually
  448. // quite fit, it might be necessary to add/subtract a fixup value. we
  449. // distribute this value as 1 or -1 over a number of registers. the total
  450. // fixup will never exceed the register range which is <16 anyway, so we
  451. // can do that. uses the global ???Scale structures to put the values
  452. void
  453. zVgaText::CalcScale(char startRGB[3], char endRGB[3], char nRange)
  454. {
  455.     int delta;
  456.  
  457.     // find the difference between the two color values
  458.     delta = endRGB[0] - startRGB[0];
  459.     // find the increment value over the range
  460.     redScale.increment = delta / nRange;
  461.     // find the difference after the icrement values are added up
  462.     redScale.fixupRange = delta % nRange;
  463.     // if we are decrementing the color value, set the fixup value
  464.     // to a negative increment and set the fixup range to positive
  465.     if( 0 > redScale.fixupRange )
  466.     {
  467.         redScale.fixupRange = -redScale.fixupRange;
  468.         redScale.fixup = -1;
  469.     }
  470.     else redScale.fixup = 1;
  471.  
  472.     delta = endRGB[1] - startRGB[1];
  473.     greenScale.increment = delta / nRange;
  474.     greenScale.fixupRange = delta % nRange;
  475.     if( 0 > greenScale.fixupRange )
  476.     {
  477.         greenScale.fixupRange = -greenScale.fixupRange;
  478.         greenScale.fixup = -1;
  479.     }
  480.     else greenScale.fixup = 1;
  481.  
  482.     delta = endRGB[2] - startRGB[2];
  483.     blueScale.increment = delta / nRange;
  484.     blueScale.fixupRange = delta % nRange;
  485.     if( 0 > blueScale.fixupRange )
  486.     {
  487.         blueScale.fixupRange = -blueScale.fixupRange;
  488.         blueScale.fixup = -1;
  489.     }
  490.     else blueScale.fixup = 1;
  491. }
  492.  
  493. // software-simulated blinking. this one works with an 8-bit attribute
  494. // (unlike the other routines which work with 4-bit attributes [0..15])
  495. // it uses bits 0..3 for the foreground and bits 4..7 for the background
  496. // attribute. the RGB color definition for the BG attribute is placed into
  497. // palettes 8-15 for the FG attribute. since palettes 0-7 are not altered
  498. // you can still use them for other special effects with the "foreground"
  499. // the new palette is not sent to the vga DAC registers (use LoadPalettes)
  500. void
  501. zVgaText::BlinkSim(char nAttrib)
  502. {
  503.     // get the RGB definition for the BG attribute from palette 0
  504.     uchar *bg = GetDacPtr((nAttrib >> 4) & 0x0F, 0);
  505.     // set the color attribute for the FG, from palettes 8-15
  506.     SetColor(nAttrib & 0x0F, (char *)bg, 8, 15);
  507. }
  508.  
  509. // tries to detect a vga card
  510. Boolean
  511. zVgaText::Detect()
  512. {
  513.     regs.x.ax = 0x1A00;
  514.     VideoInt();
  515.     return Boolean( regs.h.bl > 6 && regs.h.al == 0x1A);
  516. }
  517.  
  518. // this fades out the whole palette from its current setup to black.
  519. // it will return immediately after fading out all colors. this does
  520. // modify the vga DAC registers and it does do the palette switching
  521. // you must get rid of the timer intercept for this to work [disable()]
  522. void
  523. zVgaText::FadeOut(char aDelay)
  524. {
  525.     int i;
  526.     // set up the graded fade out for all the attributes
  527.     for( i = 0; i < 16; ++i ) GradeColor(i, "\x00\x00\x00");
  528.     LoadPalettes();
  529.     for( i = 0; i < 16; ++i )
  530.     {
  531.         regs.x.ax = 0x1013;
  532.         regs.h.bl = 1;
  533.         regs.h.bh = (char)i;
  534.         VideoInt();
  535.         delay((unsigned)aDelay);
  536.     }
  537. }
  538.  
  539. // fades in the palettes. this uses palette 0 as the base palette, which
  540. // is copied to the last one. then the first palette is set to all black
  541. // and the black is scaled to fit the final settings
  542. void
  543. zVgaText::FadeIn(char aDelay)
  544. {
  545.     int i;
  546.  
  547.     memset(dac, 0, 48);  // set the first palette to all black
  548.     for( i = 0; i < 16; ++i ) GradeColor(i, (char *)&dac[720 + (i*3)]);
  549.     LoadPalettes();
  550.     for( i = 0; i < 16; ++i )
  551.     {
  552.         regs.x.ax = 0x1013;
  553.         regs.h.bl = 1;
  554.         regs.h.bh = (char)i;
  555.         VideoInt();
  556.         delay((unsigned)aDelay);
  557.     }
  558. }
  559.  
  560. // this is the timer handler that is called by INT9 (each clock tick)
  561. // this works only when installed. it will not switch palettes if the
  562. // countdown is not 0. otherwise, it will add the 'delta' value to the
  563. // current palette number and adjust it if necessary (if it goes beyond
  564. // the limits of the palette numbers)
  565. void interrupt
  566. zVgaText::timerHandler(...)
  567. {
  568.     countdown--;
  569.     if( 0 == countdown )
  570.     {
  571.         countdown = delayTicks;
  572.         nCurPalette += delta;
  573.         if( nCurPalette < 0 || nCurPalette > 15 )
  574.         {
  575.             delta = -delta;
  576.             nCurPalette += delta;
  577.             nCurPalette += delta;
  578.         }
  579.         _asm mov ax, 0x1013
  580.         _asm mov bl, 1
  581. //        _asm mov bh, nCurPalette
  582.         _BH = nCurPalette;
  583.         _asm int 0x10;
  584.     }
  585.     timerVector(); // chain the old handler
  586. }
  587.  
  588. #undef TIMER_INTERRUPT
  589. #undef VideoInt
  590. #undef xVideoInt
  591.